package com.briup.smartcity_group1.log;

import com.briup.smartcity_group1.bean.basic.BaseLog;
import com.briup.smartcity_group1.consts.LoginApiConsts;
import com.briup.smartcity_group1.consts.TokenColumnNameConsts;
import com.briup.smartcity_group1.service.IBaseLogService;
import com.briup.smartcity_group1.utils.JwtUtils;
import com.briup.smartcity_group1.web.interceptor.TokenInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.Map;

/** 日志 aop 增强
 * @author congee(congee02 @ 163.com)
 * @date 1/4/2023 6:42 PM
 */
@Aspect
@Component
@Slf4j
public class LogAspect {

    @Autowired
    private IBaseLogService service;

    /**
     * 切入点不包括 记录日志本身的服务 {@link IBaseLogService}，防止日志记录不停止导致 StackOverFlow
     */
    @Pointcut("execution(* com.briup.smartcity_group1.service.*.*(..)) " +
            "&&" +
            "! execution(* com.briup.smartcity_group1.service.IBaseLogService.*(..)) ")
    public void logPointcut() {
    }

    /**
     * 执行日志记录。登录日志由 {@link #LoginLog(String)} 特殊处理
     * 非法 token 已经被 拦截器 {@link TokenInterceptor} 拦截，不考虑 token 非法的情况
     */
    @Before("logPointcut()")
    public void performLog() {

        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String uri = request.getRequestURI();

        // 不处理登录和注册的日志
        if (("/" + LoginApiConsts.LOGIN).equals(uri) || ("/" + LoginApiConsts.REGISTER).equals(uri)) {
            return;
        }

        // 创建对象，并设置默认值
        BaseLog baseLog = new BaseLog();
        baseLog.setLogId(null);
        baseLog.setLogTime(new Date());

        String token = request.getHeader("Authorization");
        String method = request.getMethod();

        // 不考虑 token 非法的情况
        Map<String, Object> info = JwtUtils.getInfo(token);

        String realname = info.get(TokenColumnNameConsts.REALNAME).toString();
        String username = info.get(TokenColumnNameConsts.USERNAME).toString();

        baseLog.setLogUsername(username);
        baseLog.setLogRealname(realname);
        baseLog.setLogRequestUri(uri);
        baseLog.setLogRequestMethod(method);

        service.addBaseLog(baseLog);

        log.info("日志已记录: {}", baseLog);

    }

    /**
     * 特殊处理登录日志
     * @param token 登录成功后返回的 token
     */
    @AfterReturning(pointcut = "execution(* com.briup.smartcity_group1.service.ILoginService.login(..))",
                    returning = "token")
    public void LoginLog(String token) {

        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        String uri = request.getRequestURI();

        // 创建对象，并设置默认值
        BaseLog baseLog = new BaseLog();
        baseLog.setLogId(null);
        baseLog.setLogTime(new Date());

        String method = request.getMethod();

        // 不考虑 token 非法的情况
        Map<String, Object> info = JwtUtils.getInfo(token);

        String realname = info.get(TokenColumnNameConsts.REALNAME).toString();
        String username = info.get(TokenColumnNameConsts.USERNAME).toString();

        baseLog.setLogUsername(username);
        baseLog.setLogRealname(realname);
        baseLog.setLogRequestUri(uri);
        baseLog.setLogRequestMethod(method);

        service.addBaseLog(baseLog);

        log.info("日志已记录: {}", baseLog);
    }

}
